package com.swsc.xapp.xroom;


import android.text.TextUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.swsc.xapp.enums.DefectStateEnums;
import com.swsc.xapp.model.DefectAddReqVO;
import com.swsc.xapp.model.DefectDetailResVO;
import com.swsc.xapp.model.DefectEditReqVO;
import com.swsc.xapp.model.DefectMarkerResVO;
import com.swsc.xapp.model.DefectResVO;
import com.swsc.xapp.model.DefectStatisticsResVO;
import com.swsc.xapp.model.DefectTableHeaderConditionResVO;
import com.swsc.xapp.model.PageInfo;
import com.swsc.xapp.model.StationDefectResVO;
import com.swsc.xapp.model.StationSimulateMapDrawSelectionReqVO;
import com.swsc.xapp.model.TextValueResVO;
import com.swsc.xapp.model.geo.GeoCrs;
import com.swsc.xapp.model.geo.GeoCrsProperties;
import com.swsc.xapp.model.geo.GeoFeature;
import com.swsc.xapp.model.geo.GeoGeometry;
import com.swsc.xapp.model.geo.GeoJson;
import com.swsc.xapp.offline.lhttpd.ApiException;
import com.swsc.xapp.utils.BeanUtils;
import com.swsc.xapp.utils.CodeUtils;
import com.swsc.xapp.utils.ConstantUils;
import com.swsc.xapp.utils.DateTimeUtils;
import com.swsc.xapp.utils.FileUtils;
import com.swsc.xapp.utils.NativeJSUtils;
import com.swsc.xapp.utils.ObjectMapper;
import com.swsc.xapp.utils.OfflineChangeUtils;
import com.yanzhenjie.andserver.http.multipart.MultipartFile;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeSet;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

public class OfflineBizService {
    private static volatile OfflineBizService instance;

    public static OfflineBizService getInstance(){
        if (instance == null) {
            synchronized (OfflineBizService.class) {
                if (instance == null) {
                    instance = new OfflineBizService();
                }
            }
        }
        return instance;
    }

    private OfflineBizService(){}

    /** 获取地图矢量数据(小方块) */
    public List<GeoJson> getVectorGeoJson(Integer organNo, String deviceCode, String zones) {
        List<PvDeviceInfoDO> deviceInfoDos = PvDeviceInfoService.getInstance().findByCondition(null, organNo, null, deviceCode, zones);
        List<GeoJson> geoJsons = null;
        if (null != deviceInfoDos && deviceInfoDos.size() > 0) {
            geoJsons = new ArrayList<>();
            GeoJson geoJson = new GeoJson();
            geoJson.setName("geojson");
            geoJson.setType("FeatureCollection");
            GeoCrs geoCrs = new GeoCrs();
            geoCrs.setType("name");
            GeoCrsProperties geoCrsProperties = new GeoCrsProperties();
            geoCrsProperties.setName("urn:ogc:def:crs:OGC:1.3:CRS84");
            geoCrs.setProperties(geoCrsProperties);
            geoJson.setCrs(geoCrs);
            geoJson.setFeatures(new CopyOnWriteArrayList<>());
            deviceInfoDos.parallelStream().forEach(infoDo -> {
                GeoFeature geoFeature = new GeoFeature();
                geoFeature.setType("Feature");
                Map<String, Object> properties = new HashMap<>();
                properties.put("GID", infoDo.getId());
                properties.put("id", infoDo.getGeoid());
                properties.put("DEVICE_ID", infoDo.getDeviceCode());
                properties.put("DEVICE_NAME", infoDo.getDeviceName());
                // properties.put("ROW", infoDo.getGeorow());
                // properties.put("COL", infoDo.getGeocol());
                // properties.put("REGION", infoDo.getRegion());
                properties.put("REMARK", infoDo.getRemark());
                geoFeature.setProperties(properties);
                GeoGeometry geoGeometry = new GeoGeometry();

                geoGeometry.setType(infoDo.getGeometryType());
                if (TextUtils.isEmpty(geoGeometry.getType())) {
                    geoGeometry.setType("Polygon");
                }
                geoGeometry.setCoordinates(JSONArray.parseArray(infoDo.getCoordinates(), List.class));
                geoFeature.setGeometry(geoGeometry);
                geoJson.getFeatures().add(geoFeature);
            });
            geoJsons.add(geoJson);
        }
        return geoJsons;
    }

    /** 故障点显示(地图) */
    public List<DefectMarkerResVO> defectMarker(Integer tenantNo, Integer organNo, String deviceCode, String zones, String patrolTimeStr, String state, String faultNames) {
        List<DefectMarkerResVO> vos = null;
        if(TextUtils.isEmpty(patrolTimeStr)){
            patrolTimeStr = maxPatrolTime(organNo);
        }
        List<DefectDO> defectDos = DefectService.getInstance().findByCondition(tenantNo, organNo, deviceCode, zones, patrolTimeStr, state, faultNames);
        if(null != defectDos && defectDos.size() > 0){
            vos = BeanUtils.copyListProperties(defectDos, DefectMarkerResVO.class);
        }
        return vos;
    }

    /** 故障详情 */
    public DefectDetailResVO defectDetail(Integer defectId){
        DefectDO defectDo = DefectService.getInstance().getById(defectId);
        DefectDetailResVO resVo = null;
        if(null != defectDo){
            resVo = BeanUtils.copyProperties(defectDo, DefectDetailResVO.class);
            List<Map<String, String>> imageList = new ArrayList<>();
            Map<String, String> map = null;
            // 上传的
            if (!TextUtils.isEmpty(defectDo.getFaultImg())) {
                String[] imgs = defectDo.getFaultImg().split(",");
                if (null != imgs) {
                    for (String img : imgs) {
                        map = new HashMap<>(1);
                        map.put("url", img);
                        imageList.add(map);
                    }
                }
            }
            // 自拍的红外图片
            List<InfraredImageDO> imageDos = InfraredImageService.getInstance().findByCondition(defectDo.getTenantNo(), defectDo.getOrganNo(), defectDo.getDefectNo());
            if (null != imageDos && imageDos.size() > 0) {
                for (InfraredImageDO imageDo : imageDos) {
                    map = new HashMap<>(1);
                    map.put("url", imageDo.getFileUrl());
                    map.put("imgId", imageDo.getId().toString());
                    imageList.add(map);
                }
            }
            resVo.setImageList(imageList);
        }
        return resVo;
    }

    /** 故障查询统计 */
 
    public DefectStatisticsResVO defectStatistics(Integer tenantNo, Integer organNo, String deviceCode, String zones, String patrolTimeStr, String state, String faultNames){
        List<DefectDO> dos = DefectService.getInstance().findByCondition(tenantNo, organNo, deviceCode, zones, patrolTimeStr, state, faultNames);
        DefectStatisticsResVO vo = null;
        if(null != dos && dos.size() > 0){
            String content = "故障总数:%s个, 已处理:%s个, 未处理:%s个。";
            vo = new DefectStatisticsResVO();
            vo.setTotalCount(dos.size());
            long undispose = dos.stream().filter(defectDo -> !DefectStateEnums.UNDEAL.getState().equals(defectDo.getState())).count();
            long disposed = dos.stream().filter(defectDo -> DefectStateEnums.DEAL.getState().equals(defectDo.getState())).count();
            vo.setDisposed((int) disposed);
            vo.setUndispose((int) undispose);
            content = String.format(content, dos.size(), disposed, undispose);
            Double totalLoss = dos.stream().map(DefectDO::getLoss).map(s -> null == s ? 0.0D : s).mapToDouble(Double::doubleValue).sum();
            vo.setTotalLoss(totalLoss.floatValue());
            Map<String, List<DefectDO>> map = dos.stream().collect(Collectors.groupingBy(DefectDO::getFaultName, Collectors.toList()));
            if(null != map && map.size() > 0){
                StringBuilder fsb = new StringBuilder();
                Map<String, Integer> faultTypeMap = new HashMap<>(map.size());
                int i = 0;
                for(Map.Entry<String, List<DefectDO>> entry : map.entrySet()){
                    Integer cn = null == entry.getValue() ? 0 : entry.getValue().size();
                    faultTypeMap.put(entry.getKey(), cn);
                    if(i > 0){
                        fsb.append(",");
                    }
                    fsb.append(entry.getKey()).append(":").append(cn).append("个");
                    i++;
                }
                fsb.append("。");

                vo.setFaultTypeCount(faultTypeMap);
                content = content + fsb.toString();
                vo.setContent(content);
            }
        }

        return vo;
    }

    /** 消缺数据编辑 */
    public void defectEdit(Integer id, DefectEditReqVO reqVo){
        reqVo.setId(id);
        DefectDO defectDo = DefectService.getInstance().getById(id);
        if(null != defectDo){
            boolean change = false;
            if(!TextUtils.isEmpty(reqVo.getState())){
                if(!Objects.equals(defectDo.getState(), reqVo.getState())){
                    if("1".equals(reqVo.getState())){
                        reqVo.setDealTime(DateTimeUtils.getDateTimeStr(new Date()));
                        JSONObject userInfo = NativeJSUtils.readCacheUserInfo();
                        if (null != userInfo) {
                            reqVo.setDealer(userInfo.getString("username"));
                        }
                    }else {
                        reqVo.setDealer("--");
                    }
                }
                defectDo.setState(reqVo.getState());
                change = true;
            }
            if(!TextUtils.isEmpty(reqVo.getDealer())){
                defectDo.setDealer(reqVo.getDealer());
                change = true;
            }
            if(!TextUtils.isEmpty(reqVo.getRemark())){
                defectDo.setRemark(reqVo.getRemark());
                change = true;
            }
            if(!TextUtils.isEmpty(reqVo.getDealTime())){
                defectDo.setDealTime(reqVo.getDealTime());
                change = true;
            }
            if(!TextUtils.isEmpty(reqVo.getFaultImg())){
                InfraredImageService.getInstance().deleteFaultImg(defectDo.getDefectNo(), reqVo.getFaultImg(), ConstantUils.DIR_INFRARED);
                change = true;
            }
            if(change){
                DefectService.getInstance().update(defectDo);
                OfflineChangeUtils.saveDefectChange(null != defectDo.getDefectNo() ? defectDo.getDefectNo() : Long.valueOf(defectDo.getId()));
            }

        }
    }

    /** 消缺数据列表筛选条件 */
    public DefectTableHeaderConditionResVO defectCondition(Integer organNo, String zone, String patrolTimeStr){
        DefectTableHeaderConditionResVO resVo = new DefectTableHeaderConditionResVO();

        List<Integer> organNoIn = null;
        JSONObject userInfoObj = NativeJSUtils.readCacheUserInfo();
        if(null != userInfoObj){
            JSONArray jsonArray = userInfoObj.getJSONArray("organNos");
            organNoIn = jsonArray.toJavaList(Integer.class);
        }
        if(null == organNoIn){
            organNoIn = new ArrayList<>();
        }
        if(null != organNo){
            organNoIn.add(organNo);
        }

        List<CorporationDO> corporationDos = CorporationService.getInstance().findByCondition(null , null, organNoIn);
        if(null != corporationDos && corporationDos.size() > 0){
            corporationDos.stream().forEach(ps -> {
                Double[] lnglat = new Double[]{ps.getLatitude(), ps.getLongitude()};
                resVo.getStations().add(new TextValueResVO(ps.getOrganName(), ps.getOrganNo().toString(), lnglat));
            });
        }
        if(null != organNo){
            List<DefectDO> defectPatrolTimes = DefectService.getInstance().listPatrolTimes(organNo);
            if(null != defectPatrolTimes && defectPatrolTimes.size() > 0){
                TreeSet<String> patrolTimeSet = new TreeSet<>();

                defectPatrolTimes.stream().forEach(defectDo -> {
                    if(!TextUtils.isEmpty(defectDo.getPatrolTime())){
                        patrolTimeSet.add(defectDo.getPatrolTime().substring(0, 10));
                    }
                });
                String maxPatrolTimeStr = null;
                if(null != patrolTimeSet && patrolTimeSet.size() > 0){
                    for(String pt : patrolTimeSet){
                        resVo.getPatrolTimes().add(new TextValueResVO(pt, pt));
                        if(TextUtils.isEmpty(maxPatrolTimeStr) || pt.compareTo(maxPatrolTimeStr) > 0){
                            maxPatrolTimeStr = pt;
                        }
                    }
                }
                if(!TextUtils.isEmpty(maxPatrolTimeStr)){
                    List<DefectDO> defectTypes = DefectService.getInstance().listDefectTypes(organNo, maxPatrolTimeStr);
                    if(null != defectTypes && defectTypes.size() > 0){
                        defectTypes.stream().forEach(defectDo -> {
                            resVo.getFaultNames().add(new TextValueResVO(defectDo.getFaultName(), defectDo.getFaultName()));
                        });
                    }
                }
            }
            List<DefectDO> defectZones = DefectService.getInstance().listZones(organNo, patrolTimeStr);
            if(null != defectZones && defectZones.size() > 0){
                defectZones.stream().forEach(defectDo -> {
                    resVo.getZones().add(new TextValueResVO(defectDo.getZone(), defectDo.getZone()));
                });
            }
        }
        if(null == resVo.getFaultNames() || resVo.getFaultNames().size() < 1){
            List<DefectDO> defectTypes = DefectService.getInstance().listDefectTypes(organNo, patrolTimeStr);
            if(null != defectTypes && defectTypes.size() > 0){
                defectTypes.stream().forEach(defectDo -> {
                    resVo.getFaultNames().add(new TextValueResVO(defectDo.getFaultName(), defectDo.getFaultName()));
                });
            }

        }
        return resVo;
    }

    /** 故障列表(分页) */
    public PageInfo<StationDefectResVO> defectPage(Integer tenantNo, Integer organNo, String deviceCode, String zones, String patrolTimeStr, String state, String faultNames, Integer pageNo, Integer pageSize) {
        PageInfo<StationDefectResVO> pageInfo = DefectService.getInstance().defectPage(tenantNo, organNo, deviceCode, zones, patrolTimeStr, state, faultNames, pageNo, pageSize);
        return pageInfo;
    }

    public TreeSet<String> stationZones(Integer organNo, String patrolTimeStr) {
        List<DefectDO> dos = DefectService.getInstance().listZones(organNo, patrolTimeStr);
        TreeSet<String> zoneSet = new TreeSet<>();
        if(null != dos && dos.size() > 0){
            dos.stream().forEach(defectDo -> {
                if(!TextUtils.isEmpty(defectDo.getZone())){
                    zoneSet.add(defectDo.getZone());
                }
            });
        }
        return zoneSet;
    }

    private String maxPatrolTime(Integer organNo){
        List<DefectDO> defectPatrolTimes = DefectService.getInstance().listPatrolTimes(organNo);
        if(null != defectPatrolTimes && defectPatrolTimes.size() > 0) {
            TreeSet<String> patrolTimeSet = new TreeSet<>();

            defectPatrolTimes.stream().forEach(defectDo -> {
                if (!TextUtils.isEmpty(defectDo.getPatrolTime())) {
                    patrolTimeSet.add(defectDo.getPatrolTime().substring(0, 10));
                }
            });
            String maxPatrolTimeStr = null;
            if (null != patrolTimeSet && patrolTimeSet.size() > 0) {
                for (String pt : patrolTimeSet) {
                    if (TextUtils.isEmpty(maxPatrolTimeStr) || pt.compareTo(maxPatrolTimeStr) > 0) {
                        maxPatrolTimeStr = pt;
                    }
                }
            }
            return maxPatrolTimeStr;
        }
        return null;
    }

    public List<Map<String, String>> defectInfraredImageUpload(MultipartFile file, Integer organNo, Integer defectId) {
        if(null == file || null == organNo || null == defectId){
            ApiException.isFalse((null == file || null == organNo || null == defectId), "参数不全");
        }
        DefectDO defectDo = DefectService.getInstance().getById(defectId);
        ApiException.isFalse(null == defectDo, "故障不存在");

        String fileName = file.getFilename();
        String newFilePath = ConstantUils.DIR_INFRARED.concat(String.format("%09d", organNo))
                .concat("/")
                .concat(null == defectDo.getDefectNo() ? defectDo.getId().toString() : defectDo.getDefectNo().toString())
                .concat("/")
                .concat(fileName);
        try {
            FileUtils.saveByRandomAccessFile(file.getStream(), newFilePath);
        } catch (IOException e) {
            android.util.Log.e("获取文件流", e.getMessage());
            ApiException.isFalse(true, "获取文件流错误");
        }
        InfraredImageDO infraredImageDo = saveInfaredImage(defectDo, fileName, newFilePath);
        List<Map<String, String>> finalRas = new ArrayList<>();
        Map<String, String> m = new HashMap<>(8);
        m.put("originName", fileName);
        m.put("fullPath", newFilePath);
        m.put("filePath", infraredImageDo.getFileUrl());
        if(null != infraredImageDo && null != infraredImageDo.getId()) {
            m.put("imgId", infraredImageDo.getId().toString());
        }
        finalRas.add(m);
        OfflineChangeUtils.saveDefectChange(null != defectDo.getDefectNo() ? defectDo.getDefectNo() : Long.valueOf(defectDo.getId()));
        return finalRas;
    }

    private InfraredImageDO saveInfaredImage(DefectDO defectDo, String fileName, String newFilePath){
        InfraredImageDO infraredImageDo = new InfraredImageDO();
        infraredImageDo.setTenantNo(defectDo.getTenantNo());
        infraredImageDo.setOrganNo(defectDo.getOrganNo());
        infraredImageDo.setDefectNo(defectDo.getDefectNo());
        infraredImageDo.setFileName(fileName);
        String fileUrl = newFilePath.replaceAll(ConstantUils.DIR_BASE, "");
        if(!fileUrl.startsWith("/")){
            fileUrl = "/" + fileUrl;
        }
        infraredImageDo.setFileUrl(fileUrl);
        int id = (int) (System.currentTimeMillis() / 1000);
        infraredImageDo.setId(id);
        InfraredImageService.getInstance().save(infraredImageDo);
        return infraredImageDo;
    }

    public List<Map<String, String>> defectImageUpload(MultipartFile file, Integer organNo, Integer defectId) {
        DefectDO defectDo = null;
        if(null != defectId){
            defectDo = DefectService.getInstance().getById(defectId);
            ApiException.isFalse(null == defectDo, "故障不存在");
        }
        String fileName = file.getFilename();
        String newFilePath = String.format("%09d", organNo)
                .concat("/")
                .concat(null == defectDo.getDefectNo() ? defectDo.getId().toString() : defectDo.getDefectNo().toString())
                .concat("/")
                .concat(fileName);
        if(null == defectDo){
            newFilePath = ConstantUils.DIR_IMAGE_DATA_SET_TEMP.concat(newFilePath);
        }else {
            newFilePath = ConstantUils.DIR_INFRARED.concat(newFilePath);
        }
        try {
            FileUtils.saveByRandomAccessFile(file.getStream(), newFilePath);
        } catch (IOException e) {
            android.util.Log.e("获取文件流", e.getMessage());
            ApiException.isFalse(true, "获取文件流错误");
        }
        InfraredImageDO infraredImageDo = saveInfaredImage(defectDo, fileName, newFilePath);
        List<Map<String, String>> finalRas = new ArrayList<>();
        Map<String, String> m = new HashMap<>(8);
        m.put("originName", fileName);
        m.put("fullPath", newFilePath);
        m.put("filePath", infraredImageDo.getFileUrl());
        if(null != infraredImageDo && null != infraredImageDo.getId()) {
            m.put("imgId", infraredImageDo.getId().toString());
        }
        finalRas.add(m);
        return finalRas;
    }

    public DefectResVO addDefect(DefectAddReqVO reqVo) {
        reqVo.validSingle(null);
        CorporationDO corporationDo = CorporationService.getInstance().checkStationByOrganNo(reqVo.getOrganNo());
        if(TextUtils.isEmpty(reqVo.getBatchNo())){
            reqVo.setBatchNo(CodeUtils.generateBatchNo(corporationDo.getOrganNo(), reqVo.getPatrolTime(), 1));
            int cnt = DefectService.getInstance().count(corporationDo.getTenantNo(), corporationDo.getOrganNo(), reqVo.getBatchNo(), null);
            if(cnt < 1){
                cnt = 0;
            }
            cnt += 1;
            reqVo.setDefectCode(reqVo.getBatchNo()+"-" + cnt);
        }
        int cnt = DefectService.getInstance().count(corporationDo.getTenantNo(), corporationDo.getOrganNo(), reqVo.getBatchNo(), reqVo.getDeviceCode());
        ApiException.isFalse(cnt > 0, "故障已存在, 无需重复添加");
        String newFileDir = ConstantUils.DIR_IMAGE_DATA_SET.concat(reqVo.getBatchNo());
        if(!TextUtils.isEmpty(reqVo.getFaultImg())){
            String[] faultImgArr = reqVo.getFaultImg().split(",");
            String newFaultImgStr = "";
            for(int i = 0; i < faultImgArr.length; i++){
                if(i > 0){
                    newFaultImgStr = newFaultImgStr + ",";
                }
                try {
                    String newFualtImg = FileUtils.moveFile(faultImgArr[i], newFileDir);
                    newFualtImg = newFualtImg.replaceAll(ConstantUils.DIR_BASE, "");
                    if(!newFualtImg.startsWith("/")){
                        newFualtImg = "/" + newFualtImg;
                    }
                    newFaultImgStr = newFaultImgStr + newFualtImg;
                } catch (IOException e) {
                    ApiException.isFalse(!false, "图片路径错误");
                }
            }
            reqVo.setFaultImg(newFaultImgStr);
            reqVo.generateDefectNo();
            reqVo.setTenantNo(corporationDo.getTenantNo());
            reqVo.setOrganName(corporationDo.getOrganName());
            reqVo.setState(DefectStateEnums.UNDEAL.getState());
            if(TextUtils.isEmpty(reqVo.getZone())){
                reqVo.setZone("default");
            }
            DefectDO defectDo = BeanUtils.copyProperties(reqVo, DefectDO.class);
            int id = (int) (System.currentTimeMillis() / 1000);
            defectDo.setId(id);
            DefectService.getInstance().save(defectDo);
            OfflineChangeUtils.saveDefectNew(defectDo.getId());
            return BeanUtils.copyProperties(defectDo, DefectResVO.class);
        }
        return null;
    }

    public Long drawDevice(StationSimulateMapDrawSelectionReqVO reqVo) {
        CorporationDO corporationDo = CorporationService.getInstance().checkStationByOrganNo(reqVo.getOrganNo());
        List<PvDeviceInfoDO> pvDeviceInfoDos = PvDeviceInfoService.getInstance().findByCondition(corporationDo.getTenantNo(), corporationDo.getOrganNo(), reqVo.getSelectionType(), reqVo.getSelectionCode(), null);
        ApiException.isFalse(null != pvDeviceInfoDos && pvDeviceInfoDos.size() > 0, "设备已存在");

        JSONObject feature = JSON.parseObject(reqVo.getSelectionGeojson());
        JSONObject geometry = feature.getJSONObject("geometry");
        ApiException.isFalse(null == geometry || !geometry.containsKey("coordinates"), "geojson数据不完整");
        PvDeviceInfoDO pvDeviceInfoDo = new PvDeviceInfoDO();
        pvDeviceInfoDo.setTenantNo(corporationDo.getTenantNo());
        pvDeviceInfoDo.setOrganNo(corporationDo.getOrganNo());
        pvDeviceInfoDo.setOrganName(corporationDo.getOrganName());
        pvDeviceInfoDo.setDeviceName(reqVo.getSelectionName());
        pvDeviceInfoDo.setDeviceModel(reqVo.getSelectionModel());
        pvDeviceInfoDo.setDeviceCode(reqVo.getSelectionCode());
        pvDeviceInfoDo.setDeviceRawCode(reqVo.getSelectionCode());
        pvDeviceInfoDo.setDeviceType(reqVo.getSelectionType());
        pvDeviceInfoDo.setGeometryType(geometry.getString("type"));
        pvDeviceInfoDo.setCoordinates(geometry.getString("coordinates"));
        pvDeviceInfoDo.setId(System.currentTimeMillis());
        PvDeviceInfoService.getInstance().save(pvDeviceInfoDo);
        return pvDeviceInfoDo.getId();
    }
}
